package com.chen.base.module.redis.inter;

import com.chen.base.inter.LinkNodeHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;

import javax.annotation.Resource;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

/**
 * 抽象redis队列监听类
 * @Author: 陈锦龙
 * @Date: 2025/7/1 20:42
 */
@Slf4j
public abstract class AbstractRedisQueueListen implements LinkNodeHandler<Object, Object> {

    @Resource
    public RedisTemplate<String, Object> redisTemplate;

    /**
     * 主要消费逻辑
     */
    @Override
    public Object handler(Object params) throws Exception {
        CompletableFuture.runAsync(() -> {
            while (true){
                try {
                    // 以阻塞的方式从队列中获取值
                    Object value = redisTemplate.opsForList().rightPopAndLeftPush(sourceKey(), destinationKey(), timeout(), unit());
                    if (value != null){
                        customer(value);
                        historyCustomer();
                    }
                }catch (Exception e){
                    log.error("{} 队列消费异常: {}", this.getClass().getSimpleName(), e);
                }
            }
        });
        return null;
    }

    /**
     * 数据消费
     * @param value 从队列中取出的值
     */
    public abstract void customer(Object value);

    /**
     * 队列的key
     * @return 队列的key
     */
    public abstract String sourceKey();

    /**
     * 数据历史消费的key
     * @return 数据历史消费的key
     */
    public String destinationKey(){
        return sourceKey() + "_history";
    }

    /**
     * 保留多少条历史消费的记录
     */
    public void historyCustomer(){
        Long size = redisTemplate.opsForList().size(destinationKey());
        if (size != null && size > 50){
            redisTemplate.opsForList().rightPop(destinationKey());
        }
    }

    /**
     * 获取队列的值超时时间
     * @return 超时时间
     */
    public long timeout(){
        return 10;
    }

    /**
     * 获取队列的值超时时间单位
     * @return 超时时间单位
     */
    public TimeUnit unit(){
        return TimeUnit.SECONDS;
    }
}
